﻿using AutoMapper;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.Logss;
using Quartz;
using Snap7;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HamcoWcs.Workers.PconWorkers
{
    /// <summary>
    /// 设备InterLock日志后台服务
    /// </summary>
    [DisallowConcurrentExecution]
    public class InterLockWorker : WorkerBase
    {
        private static List<InterLockInfo> interLockInfos = new List<InterLockInfo>()
        {
            new InterLockInfo("CJVCV200","CJSTW100",0,4),
            new InterLockInfo("CJVCV800","CJSTW100",4,4),
            new InterLockInfo("CJVCV700","CJSTW100",8,4),
            new InterLockInfo("CJRCV400","CJSTW100",12,4),
            new InterLockInfo("CJRCV300","CJSTW100",16,4),
            new InterLockInfo("CJVCV100","CJSTW100",20,4),

            new InterLockInfo("CJVCV400","CJSTW200",24,4),
            new InterLockInfo("CJVCV300","CJSTW200",28,4),
            new InterLockInfo("CJVCV200","CJSTW200",32,4),
            new InterLockInfo("CJVCV100","CJSTW200",36,4),
            new InterLockInfo("CJRCV200","CJSTW200",40,4),
            new InterLockInfo("CJRCV100","CJSTW200",44,4),
        };


        private static List<InterLockInfo_Siasun> interLockInfos_Siasun = new List<InterLockInfo_Siasun>()
        {
            new InterLockInfo_Siasun("CJMCV100","CJPPK100",48,4),
            new InterLockInfo_Siasun("CJMCV200","CJPPK200",52,4),
            new InterLockInfo_Siasun("CJMCV300","CJPPK300",56,4),
            new InterLockInfo_Siasun("CJMCV400","CJPPK400",60,4),
            new InterLockInfo_Siasun("CJMCV500","CJPPK500",64,4),
            new InterLockInfo_Siasun("CJMCV600","CJPPK600",68,4),
            new InterLockInfo_Siasun("CJMCV700","CJPPK700",72,4),
            new InterLockInfo_Siasun("CJMCV800","CJPPK800",76,4),
            new InterLockInfo_Siasun("CJMCV900","CJPPK900",80,4),
            //new InterLockInfo_Siasun("CJMCVA00","SA",84,4),

        };

        public override Task Execute(IJobExecutionContext context)
        {
            //return Task.CompletedTask;

            if (!_connectionState)
                ConnectPlc();
            if (!_connectionState) return Task.CompletedTask;

            try
            {
                var recv = new byte[_length];
                var res = _client.DBRead(105, 0, _length, recv);
                if (res != 0)
                {
                    throw new Exception("InterLockWorker:Read DB105 Error");
                }

                foreach (InterLockInfo inter in interLockInfos)
                {
                    inter.Update(recv, _wcsDbContext);
                }

                foreach (var inter in interLockInfos_Siasun)
                {
                    inter.Update(recv, _wcsDbContext);
                }
            }
            catch (Exception ex)
            {
                _logger.AddSystemErrorLog(ex.Message);
                _client.Disconnect();
                _connectionState = false;
            }

            return Task.CompletedTask;
        }

        private void ConnectPlc()
        {
            var res = _client.ConnectTo(_plcip, 0, 1);
            if (res != 0)
            {
                Console.WriteLine("interlock error");
            }
            _connectionState = res == 0;
        }


        private readonly IMonitorBaseService _monitorBaseService;

        public InterLockWorker(IMonitorBaseService monitorBaseService, WcsDbContext wcsDbContext, IMapper mapper, ILoggerService logger) : base(wcsDbContext, mapper, logger)
        {
            _monitorBaseService = monitorBaseService;
        }

        private static bool _connectionState;
        private static S7Client _client;
        private static string _plcip;
        private static int _length;
        static InterLockWorker()
        {
            _client = new S7Client();
            _plcip = "10.45.216.101";
            _connectionState = false;
            _length = 84;
        }
    }

    public class InterLockInfo_Siasun
    {
        public InterLockInfo_Siasun(string from, string to, int offset, int length)
        {
            From = from;
            To = to;
            Offset = offset;
            Length = length;
        }
        public string Direction { get; set; }
        public string From { get; set; }
        public string To { get; set; }

        public int Offset { get; set; }
        public int Length { get; set; }

        #region Property


        [InterLockSetting("自动运行中", 0, 1, "PCON >> SIASUN")]
        public int X1 { get; set; }
        [InterLockSetting("S", 0, 2, "PCON >> SIASUN")]
        public int X2 { get; set; }
        [InterLockSetting("正向模式", 0, 3, "PCON >> SIASUN")]
        public int X3 { get; set; }
        [InterLockSetting("进入请求", 0, 4, "PCON >> SIASUN")]
        public int X4 { get; set; }
        [InterLockSetting("辊道正向运行中", 0, 5, "PCON >> SIASUN")]
        public int X5 { get; set; }
        [InterLockSetting("S_1", 0, 6, "PCON >> SIASUN")]
        public int X6 { get; set; }
        [InterLockSetting("S_2", 0, 7, "PCON >> SIASUN")]
        public int X7 { get; set; }
        [InterLockSetting("S_3", 1, 0, "PCON >> SIASUN")]
        public int X8 { get; set; }
        [InterLockSetting("反向模式", 1, 1, "PCON >> SIASUN")]
        public int X9 { get; set; }
        [InterLockSetting("辊道无载", 1, 2, "PCON >> SIASUN")]
        public int X10 { get; set; }
        [InterLockSetting("允许退栈板", 1, 3, "PCON >> SIASUN")]
        public int X11 { get; set; }
        [InterLockSetting("辊道反向运行中", 1, 4, "PCON >> SIASUN")]
        public int X12 { get; set; }
        [InterLockSetting("进入完成", 1, 5, "PCON >> SIASUN")]
        public int X13 { get; set; }
        [InterLockSetting("S_5", 1, 6, "PCON >> SIASUN")]
        public int X14 { get; set; }
        [InterLockSetting("S_6", 1, 7, "PCON >> SIASUN")]
        public int X15 { get; set; }


        [InterLockSetting("自动运行中", 2, 1, "PCON << SIASUN")]
        public int Y1 { get; set; }
        [InterLockSetting("S", 2, 2, "PCON << SIASUN")]
        public int Y2 { get; set; }
        [InterLockSetting("正向模式", 2, 3, "PCON << SIASUN")]
        public int Y3 { get; set; }
        [InterLockSetting("辊道无载", 2, 4, "PCON << SIASUN")]
        public int Y4 { get; set; }
        [InterLockSetting("允许进入", 2, 5, "PCON << SIASUN")]
        public int Y5 { get; set; }
        [InterLockSetting("完全进入", 2, 6, "PCON << SIASUN")]
        public int Y6 { get; set; }
        [InterLockSetting("上料完成", 2, 7, "PCON << SIASUN")]
        public int Y7 { get; set; }
        [InterLockSetting("S_3", 3, 0, "PCON << SIASUN")]
        public int Y8 { get; set; }
        [InterLockSetting("反向模式", 3, 1, "PCON << SIASUN")]
        public int Y9 { get; set; }
        [InterLockSetting("退栈板请求", 3, 2, "PCON << SIASUN")]
        public int Y10 { get; set; }
        [InterLockSetting("反向运行中", 3, 3, "PCON << SIASUN")]
        public int Y11 { get; set; }
        [InterLockSetting("栈板完全流出", 3, 4, "PCON << SIASUN")]
        public int Y12 { get; set; }
        [InterLockSetting("上料NG", 3, 5, "PCON << SIASUN")]
        public int Y13 { get; set; }
        [InterLockSetting("S_5", 3, 6, "PCON << SIASUN")]
        public int Y14 { get; set; }
        [InterLockSetting("S_6", 3, 7, "PCON << SIASUN")]
        public int Y15 { get; set; }

        #endregion


        public void Update(byte[] recv, WcsDbContext wcsDbContext)
        {

            var a = recv.Skip(Offset).Take(Length).ToArray();
            //var logs = new List<CommunicationLog>();
            var logs = new List<InterlockLog>();
            foreach (var pi in this.GetType().GetProperties())
            {

                var attr = pi.GetCustomAttribute<InterLockSettingAttribute>();

                if (attr is null) continue;
                var n = (a[attr.ByteOffset] >> attr.BitOffset) & 1;
                var o = (int)pi.GetValue(this);

                StringBuilder sb = new StringBuilder();
                foreach (var t in a)
                {
                    sb.Append(Convert.ToString(t, 2).PadLeft(8, '0'));
                    sb.Append(" ");
                }

                if (o != n)
                {
                    var s = attr.Direction == "PCON >> SIASUN" ? From : To;
                    var r = attr.Direction == "PCON >> SIASUN" ? To : From;

                    pi.SetValue(this, n);

                    logs.Add(new InterlockLog()
                    {
                        TransactionId = $"pcon{DateTime.Now:yyyyMMddHHmmssffffff}",
                        Direction = attr.Direction,
                        Receiver = r,
                        Sender = s,
                        Content = $"[{attr.Name}:{o}->{n}][{sb}]",
                        MessageName = attr.Name,
                        CreatedTime = DateTime.Now,
                    });

                }
            }
            wcsDbContext.Set<InterlockLog>().AddRange(logs);
            wcsDbContext.SaveChanges();
        }
    }

    public class InterLockInfo
    {
        public InterLockInfo(string from, string to, int offset, int length)
        {
            From = from;
            To = to;
            Offset = offset;
            Length = length;
        }
        public string Direction { get; set; }
        public string From { get; set; }
        public string To { get; set; }

        public int Offset { get; set; }
        public int Length { get; set; }

        #region Property

        [InterLockSetting("允许取货", 0, 1, "PCON >> SRM")]
        public int AllowPickUp { get; set; }
        [InterLockSetting("取货完成应答", 0, 2, "PCON >> SRM")]
        public int PickUpCompleteAck { get; set; }
        [InterLockSetting("允许卸货", 0, 3, "PCON >> SRM")]
        public int AllowPickDown { get; set; }
        [InterLockSetting("卸货完成应答", 0, 4, "PCON >> SRM")]
        public int PickDownCompleteAck { get; set; }
        [InterLockSetting("站台冲出信号", 0, 5, "PCON >> SRM")]
        public int RushOutSingal { get; set; }
        [InterLockSetting("光栅屏蔽信号", 0, 6, "PCON >> SRM")]
        public int RasterBypassSingal { get; set; }
        [InterLockSetting("请求取货", 2, 1, "PCON << SRM")]
        public int PickUpRequest { get; set; }
        [InterLockSetting("取货完成", 2, 2, "PCON << SRM")]
        public int PickUpComplete { get; set; }
        [InterLockSetting("请求卸货", 2, 3, "PCON << SRM")]
        public int PickDownRequest { get; set; }
        [InterLockSetting("卸货完成", 2, 4, "PCON << SRM")]
        public int PickDownComplete { get; set; }
        [InterLockSetting("允许移动", 2, 5, "PCON << SRM")]
        public int AllowMove { get; set; }

        #endregion

        public void Update(byte[] recv, WcsDbContext wcsDbContext)
        {

            var a = recv.Skip(Offset).Take(Length).ToArray();
            //var logs = new List<CommunicationLog>();
            var logs = new List<InterlockLog>();
            foreach (var pi in this.GetType().GetProperties())
            {
                //if (From != "CJVCV400") continue;

                var attr = pi.GetCustomAttribute<InterLockSettingAttribute>();

                if (attr is null) continue;
                var n = (a[attr.ByteOffset] >> attr.BitOffset) & 1;
                var o = (int)pi.GetValue(this);

                StringBuilder sb = new StringBuilder();
                foreach (var t in a)
                {
                    sb.Append(Convert.ToString(t, 2).PadLeft(8, '0'));
                    sb.Append(" ");
                }

                if (o != n)
                {
                    var s = attr.Direction == "PCON >> SRM" ? From : To;
                    var r = attr.Direction == "PCON >> SRM" ? To : From;

                    pi.SetValue(this, n);

                    logs.Add(new InterlockLog()
                    {
                        TransactionId = $"pcon{DateTime.Now:yyyyMMddHHmmssffffff}",
                        Direction = attr.Direction,
                        Receiver = r,
                        Sender = s,
                        Content = $"[{attr.Name}:{o}->{n}][{sb}]",
                        MessageName = attr.Name,
                        CreatedTime = DateTime.Now,
                    });

                }
            }
            wcsDbContext.Set<InterlockLog>().AddRange(logs);
            wcsDbContext.SaveChanges();
        }

    }
    public class InterLockSettingAttribute : Attribute
    {
        public InterLockSettingAttribute(string name, int byteOffset, int bitOffset, string direction)
        {
            Name = name;
            ByteOffset = byteOffset;
            BitOffset = bitOffset;
            Direction = direction;
        }

        public string Name { get; set; }
        public int ByteOffset { get; set; }
        public int BitOffset { get; set; }
        public string Direction { get; set; }
    }
}
